package dev.ece.suit.hexmap;

import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import com.bulletphysics.collision.shapes.CollisionShape;

import dev.ece.core.cells.model.AbstractModel;
import dev.ece.core.cells.model.ModelCollisionShape;
import dev.ece.core.engine.Engine;
import dev.ece.core.light.Material;
import dev.ece.core.texture.FBOS;
import dev.ece.core.texture.Texture;
import dev.ece.suit.hexmap.terrain.TerrainFactory;
import dev.ece.suit.skybox.SkyBox;
import dev.ece.util.lib.Vector3f;
import dev.ece.util.tools.Camera;

@Deprecated
public class HexMapModel extends AbstractModel<Float> implements ModelCollisionShape {

	/**
	 * 地面纹理集合
	 */
	private Texture[] textures;
	
	private int[][] terrainTypes;
	
	private int rows;
	
	private int cols;
	
	private float distance = 0;
	
	private HexMapChunks chunks;
	
	/**
	 * 主体地图片元
	 */
	private HexMapCell[][] cells;
	
	/**
	 * 边线接缝
	 */
	private List<HexMapCrevice> crevices;
	/**
	 * 三角接缝
	 */
	private List<HexMapTriangle> triangles;
	/**
	 * 水地图图元
	 */
	private List<HexMapWaterCell> waters;
	
	private HexMapCellShader hexMapCellShader;
	
	private HexMapCreviceShader hexMapCreviceShader;
	
	private HexMapTriangleShader hexMapTriangleShader;
	
	private HexMapWaterShader hexMapWaterShader;
	
	private TerrainFactory terrainFactory;
	
	private Texture noise;
	
	private Material waterMaterial;
	
	private SkyBox skybox;
	
	public HexMapModel(int[][] terrainTypes, SkyBox skybox, TerrainFactory terrainFactory, HexMapChunks chunks) {
		this.terrainTypes = terrainTypes;
		this.skybox = skybox;
		this.terrainFactory = terrainFactory;
		this.chunks = chunks;
		this.init();
	}
	
	protected void init() {
		this.rows = this.terrainTypes.length;
		this.cols = this.terrainTypes[0].length;
		this.waterMaterial = terrainFactory.createWaterMaterial();
		
		this.cells = terrainFactory.createHexMapCells(chunks, terrainTypes);
		this.crevices = terrainFactory.createHexMapCrevices(chunks, cells);
		this.triangles = terrainFactory.createHexMapTriangles(chunks, cells);
		this.waters = terrainFactory.createHexMapWaterCells(chunks, cells);
		
		this.hexMapCellShader = createHexMapCellShader();
		this.hexMapCreviceShader = createHexMapCreviceShader();
		this.hexMapTriangleShader = createHexMapTriangleShader();
		this.hexMapWaterShader = createHexMapWaterShader();
		this.noise = terrainFactory.createWaterNoiseTexture();
		this.textures = terrainFactory.createTextures();
		
		this.chunks.setup(this);
	}
	
	protected HexMapWaterShader createHexMapWaterShader() {
		return HexMapWaterShader.createHexMapWaterShader();
	}
	
	protected HexMapTriangleShader createHexMapTriangleShader() {
		return HexMapTriangleShader.createHexMapTriangleShader();
	}
	
	protected HexMapCreviceShader createHexMapCreviceShader() {
		return HexMapCreviceShader.createHexMapCreviceShader();
	}
	
	protected HexMapCellShader createHexMapCellShader() {
		return HexMapCellShader.createHexMapCellShader();
	}
	
	@Override
	public void onInitialize() {
		chunks.initialize();
		System.gc();
	}

	@Override
	public void onRenderDepthMap(Camera camera, Float value) {
		chunks.renderDepthMap();
	}
	
	@Override
	public void onRender(Camera camera, Float value) {
		hexMapCellShader.glUseProgram();
		hexMapCellShader.glModelViewProjectMatrix();
		chunks.render(hexMapCellShader, textures);
		
		//绘制连接缝隙
		hexMapCreviceShader.glUseProgram();
		hexMapCreviceShader.glModelViewProjectMatrix();
		chunks.render(hexMapCreviceShader, textures);
		
		//绘制三角接缝
		hexMapTriangleShader.glUseProgram();
		hexMapTriangleShader.glModelViewProjectMatrix();
		chunks.render(hexMapTriangleShader, textures);
	}

	@Override
	public void onRenderAlpha(FBOS defer, Camera camera, Float value) {
		//绘制水
		hexMapWaterShader.glUseProgram();
		hexMapWaterShader.glModelViewProjectMatrix();
		hexMapWaterShader.glCamera(camera);
		hexMapWaterShader.glNoise(noise);
		hexMapWaterShader.glSkyBox(skybox.getTextureCube());
		hexMapWaterShader.glMaterial(waterMaterial);
		hexMapWaterShader.glDefer(defer);
		distance += Engine.currentTimer().getDalyTime() / 10f;
		hexMapWaterShader.glDistance(distance);
		chunks.render(hexMapWaterShader);
	}

	/**
	 * 射线相交
	 * @param o 射线起点
	 * @param dir 方向
	 * @param result 返回结果,返回true，则设置交点坐标
	 * @return 是否相交
	 */
	public boolean isIntersected(Vector3f o, Vector3f dir, HexMapPickUp hexMapPickUp) {
		int row = (int) (o.getZ() / (terrainFactory.getCellOutSize() * 2f * Math.sin(Math.toRadians(60))));
		int col = (int) ((o.getX() - (row % 2) * terrainFactory.getCellOutSize()) / (terrainFactory.getCellOutSize() * 2f));
		if(col >= cols || col < 0) {
			return false; 
		}
		if(row >= rows || row < 0) {
			return false; 
		}
		return isIntersected(new HexMapCell[] {cells[row][col]}, o, dir, hexMapPickUp, 3);
	}
	
	protected boolean isIntersected(HexMapCell[] cells, Vector3f o, Vector3f dir, HexMapPickUp hexMapPickUp, int floors) {
		if(floors < 0) {
			return false;
		}
		HexMapCell[] hexMapCells = cells;
		HexMapCrevice crevice = null;
		HexMapTriangle triangle = null;
		//周围
		Set<HexMapCell> rounds = new HashSet<HexMapCell>();
		for(HexMapCell cell:hexMapCells) {
			if(cell == null) {
				continue;
			}
			if(cell.isIntersected(o, dir, hexMapPickUp)) {
				return true;
			}
			for(int n=0; n<6; n++) {
				crevice = cell.getCrevices()[n];
				if(crevice != null && crevice.isIntersected(o, dir, hexMapPickUp)) {
					return true;
				}
				triangle = cell.getTriangles()[n];
				if(triangle != null && triangle.isIntersected(o, dir, hexMapPickUp)) {
					return true;
				}
			}
			for(HexMapCell round: cell.getCells()) {
				if(round != null) {
					rounds.add(round);
				}
			}
		}
		//拾取周围
		if(!rounds.isEmpty() && isIntersected(rounds.toArray(new HexMapCell[] {}), o, dir, hexMapPickUp, floors - 1)) {
			return true;
		}
		return false;
	}
	
	public int[][] getTerrainTypes() {
		return terrainTypes;
	}

	public HexMapChunks getChunks() {
		return chunks;
	}

	public Texture[] getTextures() {
		return textures;
	}

	@Override
	public CollisionShape createCollisionShape() {
		return terrainFactory.createCollisionShape(this.rows, this.cols, cells, crevices, triangles, waters);
	}

	public int getRows() {
		return rows;
	}

	public int getCols() {
		return cols;
	}

	public HexMapCell[][] getCells() {
		return cells;
	}

	public List<HexMapCrevice> getCrevices() {
		return crevices;
	}

	public List<HexMapTriangle> getTriangles() {
		return triangles;
	}

	public List<HexMapWaterCell> getWaters() {
		return waters;
	}

	public TerrainFactory getTerrainFactory() {
		return terrainFactory;
	}

	public SkyBox getSkybox() {
		return skybox;
	}

	@Override
	public void destroy() {
		if(cells != null) {
			for(HexMapCell[] row:cells) {
				for(HexMapCell cell: row) {
					cell.destroy();
				}
			}
		}
		if(crevices != null) {
			Iterator<HexMapCrevice> it = crevices.iterator();
			while(it.hasNext()) {
				it.next().destroy();
			}
		}
		if(triangles != null) {
			Iterator<HexMapTriangle> it = this.triangles.iterator();
			while(it.hasNext()) {
				it.next().destroy();
			}
		}
		if(waters != null) {
			Iterator<HexMapWaterCell> it = this.waters.iterator();
			while(it.hasNext()) {
				it.next().destroy();
			}
		}
		chunks.destroy();
		terrainTypes = null;
		textures = null;
		cells = null;
		crevices = null;
		triangles = null;
		waters = null;
		chunks = null;
		skybox = null;
	}

	
}
